﻿using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace BabelUI
{
    /// <summary>
    /// A lightweight gradient panel used by HotHTML
    /// </summary>
    public class GradientPanel : Panel
    {
        #region eBorderSide enum

        public enum eBorderSide
        {
            Top,
            Bottom,
            Left,
            Right,
            All,
            None
        }

        #endregion

        #region Fields

        private Color m_BorderColor;
        private eBorderSide m_BorderSide;
        private int m_BorderWidth;
        private Color m_GradientEnd;
        private LinearGradientMode m_GradientMode;
        private Color m_GradientStart;
        private Image m_Image;
        private Point m_ImageLocation;
        private string m_DescriptionText;
        private string m_HeaderText;
        private Point m_HeaderLocation;
        private Point m_DescriptionLocation;
        private Color m_HeaderColor;
        private Color m_DescriptionColor;
        private bool m_AntiAlias;
        private Font m_HeaderFont;
        private Font m_DescriptionFont;
        private bool m_NormaliseTextLocations;
        #endregion

        public GradientPanel()
        {
            SetStyle(ControlStyles.DoubleBuffer, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            BorderWidth = 1;
            GradientStart = SystemColors.ControlLight;
            GradientEnd = SystemColors.ControlDark;
            BorderSide = eBorderSide.All;
            ImageLocation = new Point(4, 4);
            HeaderLocation = new Point(4, 4);
            DescriptionLocation = new Point(4, 4);
            HeaderColor = SystemColors.ControlText;
            DescriptionColor = SystemColors.GrayText;
            HeaderFont = new Font(base.Font, FontStyle.Bold);
            DescriptionFont = base.Font;
        }

        #region Properties

        [Browsable(true), Category(Categories.Appearance)]
        [DefaultValue("4,4")]
        public Point ImageLocation
        {
            get { return m_ImageLocation; }
            set
            {
                m_ImageLocation = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public eBorderSide BorderSide
        {
            get { return m_BorderSide; }
            set
            {
                m_BorderSide = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public Image Image
        {
            get { return m_Image; }
            set
            {
                m_Image = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        [DefaultValue("Color.Empty")]
        public Color BorderColor
        {
            get { return m_BorderColor; }
            set
            {
                m_BorderColor = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        [DefaultValue(1)]
        public int BorderWidth
        {
            get { return m_BorderWidth; }
            set
            {
                m_BorderWidth = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        [DefaultValue("Color.Empty")]
        public Color GradientStart
        {
            get { return m_GradientStart; }
            set
            {
                m_GradientStart = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        [DefaultValue("Color.Empty")]
        public Color GradientEnd
        {
            get { return m_GradientEnd; }
            set
            {
                m_GradientEnd = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        [DefaultValue("LinearGradientMode.Vertical")]
        public LinearGradientMode GradientMode
        {
            get { return m_GradientMode; }
            set
            {
                m_GradientMode = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public string DescriptionText
        {
            get { return m_DescriptionText; }
            set
            {
                m_DescriptionText = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public string HeaderText
        {
            get { return m_HeaderText; }
            set
            {
                m_HeaderText = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public Point HeaderLocation
        {
            get { return m_HeaderLocation; }
            set
            {
                m_HeaderLocation = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public Point DescriptionLocation
        {
            get { return m_DescriptionLocation; }
            set
            {
                m_DescriptionLocation = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public Color HeaderColor
        {
            get { return m_HeaderColor; }
            set
            {
                m_HeaderColor = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public Color DescriptionColor
        {
            get { return m_DescriptionColor; }
            set
            {
                m_DescriptionColor = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        [DefaultValue(true)]
        public bool AntiAlias
        {
            get { return m_AntiAlias; }
            set
            {
                m_AntiAlias = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public Font DescriptionFont
        {
            get { return m_DescriptionFont; }
            set
            {
                m_DescriptionFont = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        public Font HeaderFont
        {
            get { return m_HeaderFont; }
            set
            {
                m_HeaderFont = value;
                Invalidate();
            }
        }

        [Browsable(true), Category(Categories.Appearance)]
        [DefaultValue(true)]
        public bool NormaliseTextLocations
        {
            get { return m_NormaliseTextLocations; }
            set
            {
                m_NormaliseTextLocations = value;
                Invalidate();
            }
        }

        #endregion

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);
            e.Graphics.SmoothingMode = AntiAlias ? SmoothingMode.AntiAlias : SmoothingMode.Default;
            DrawGradient(e.Graphics);
            DrawBorder(e.Graphics);
            DrawImage(e.Graphics);
            DrawText(e.Graphics);
        }

        /// <summary>
        /// Draws the text.
        /// </summary>
        /// <param name="graphics">The graphics.</param>
        private void DrawText(Graphics graphics)
        {
            // Need to do something about normalising text.
            using(SolidBrush brush =  new SolidBrush(HeaderColor))
            {
                graphics.DrawString(HeaderText, HeaderFont, brush, HeaderLocation);
            }

            using (SolidBrush brush = new SolidBrush(DescriptionColor))
            {
                graphics.DrawString(DescriptionText, DescriptionFont, brush, DescriptionLocation);
            }
        }

        /// <summary>
        /// Draws the gradient.
        /// </summary>
        /// <param name="graphics">The graphics.</param>
        private void DrawGradient(Graphics graphics)
        {
            // Draw Gradient background
            if (!GradientStart.IsEmpty && !GradientEnd.IsEmpty)
            {
                using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, GradientStart, GradientEnd, GradientMode))
                {
                    graphics.FillRectangle(brush, ClientRectangle);
                }
            }
        }

        /// <summary>
        /// Draws the border.
        /// </summary>
        /// <param name="graphics">The graphics.</param>
        private void DrawBorder(Graphics graphics)
        {
            // Draw border
            if (!BorderColor.IsEmpty)
            {
                using (Pen pen = new Pen(BorderColor, BorderWidth))
                {
                    if (BorderSide == eBorderSide.All)
                    {
                        Rectangle borderRect = new Rectangle(ClientRectangle.Location, new Size(ClientRectangle.Size.Width - 1, ClientRectangle.Height - 1));
                        graphics.DrawRectangle(pen, borderRect);
                    }
                    else 
                    {
                        if(BorderSide == eBorderSide.Bottom)
                        {
                            graphics.DrawLine(pen, ClientRectangle.X, ClientRectangle.Height, ClientRectangle.Width, ClientRectangle.Height);
                        }
                        else if (BorderSide == eBorderSide.Top)
                        {
                            graphics.DrawLine(pen, ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Y);
                        }
                        else if (BorderSide == eBorderSide.Left)
                        {
                            graphics.DrawLine(pen, ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Y, ClientRectangle.Height);
                        }
                        else if (BorderSide == eBorderSide.Right)
                        {
                            graphics.DrawLine(pen, ClientRectangle.Width, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Draws the image.
        /// </summary>
        /// <param name="graphics">The graphics.</param>
        private void DrawImage(Graphics graphics)
        {
            if (Image != null)
            {
                graphics.DrawImageUnscaled(Image, ImageLocation);
            }
        }

        #region Nested type: Categories

        internal class Categories
        {
            public const string Appearance = "Appearance";
        }

        #endregion
    }
}